package com.lam.code.configuration.shiro;

import com.lam.code.configuration.prop.ShiroProperties;
import com.lam.code.entity.User;
import com.lam.code.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.List;

/**
 * @author lam
 * @description 用户登录验证域
 * @date 2019/12/25 0:20
 */
public class DBRealm extends AuthorizingRealm {

    private ShiroProperties shiroProperties;

    private UserService userService;

    public DBRealm(UserService userService, ShiroProperties shiroProperties) {
        this.userService = userService;
        this.shiroProperties = shiroProperties;
        //因为数据库中的密码做了散列，所以使用shiro的散列Matcher
        this.setCredentialsMatcher(new HashedCredentialsMatcher(Sha256Hash.ALGORITHM_NAME));
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }

    /**
     *  这一步我们根据token给的用户名，去数据库查出加密过用户密码，然后把加密后的密码和盐值一起发给shiro，让它做比对
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
        String userCode = usernamePasswordToken.getUsername();
        User user = userService.getUserInfoByCode(userCode);
        if(user == null) {
            throw new AuthenticationException("用户名或密码错误");
        }

        return new SimpleAuthenticationInfo(user,
                user.getEncryptPwd(),
                ByteSource.Util.bytes(shiroProperties.getEncryptSalt()),
                this.getName());
    }

    /**
     * 这里需要注意一下的就是Shiro默认不会缓存角色信息，所以这里调用service的方法获取角色强烈建议从缓存中获取。
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        User user = (User) principals.getPrimaryPrincipal();

        //TODO test add admin
        if (user.getUsername().equals("admin")){
            simpleAuthorizationInfo.addRole("admin");
        }

        List<String> permissions = userService.getPermissionByUseId(user.getId());
        for (String permission : permissions) {
            simpleAuthorizationInfo.addStringPermission(permission);
        }
        return simpleAuthorizationInfo;
    }
}
